package main

import (
	"fmt"
	"github.com/guonaihong/gout"
	"gorm.io/driver/mysql"
	"gorm.io/gorm"
	"math/rand"
	"strconv"
	"sync"
	"sync/atomic"
	"time"
)

type Users struct {
	Id     int    `gorm:"column:id"`
	Mobile string `gorm:"column:mobile"`
	Name   string `gorm:"column:name"`
}

const (
	NUMBER    = 200
	PROCESSES = 20
	SIZE      = 10
)

var FACTORS = [][]int{{200, 235}, {300, 233}, {500, 234}}

func main() {
	dsn := "root:password@tcp(127.0.0.1:3306)/test?charset=utf8mb4&parseTime=True&loc=Local"
	db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
	if err != nil {
		panic("db error")
	}

	sqlDb, pErr := db.DB()
	if pErr != nil {
		panic("db error")
	}
	sqlDb.SetMaxIdleConns(10)
	sqlDb.SetMaxOpenConns(100)
	sqlDb.SetConnMaxLifetime(time.Hour)

	for _, factor := range FACTORS {
		factor := factor
		var users []*Users
		rand.Seed(time.Now().UnixNano())
		db.Raw("SELECT id, mobile, name " +
			"FROM users WHERE mobile <> '' and status = 1 " +
			"and LEFT(mobile, 1) = '1' and LENGTH(mobile) = 11 " +
			"order by created_at desc LIMIT " +
			strconv.Itoa(rand.Intn(10)) + "00, " + strconv.Itoa(factor[0])).
			Scan(&users)

		var token_list []string
		//var token_map = sync.Map{}
		//token_chan := make(chan string, len(users))
		//go func() {
		var twg sync.WaitGroup
		var lock sync.RWMutex
		//twg.Add(NUMBER)
		twg.Add(factor[0])
		var start_time int64 = time.Now().UnixNano() / 1e6
		for i := 0; i < factor[0]/SIZE; i++ {
			i := i
			go func() {
				defer func() {
					if err := recover(); err != nil {
						fmt.Println("get token err：", err)
						twg.Done()
					}
				}()

				for _, u := range users[i*SIZE : (i+1)*SIZE] {
					gout.POST("https://dev.tiktok.api.vodeshop.com/api/v1/send-sms-code").
						SetJSON(gout.H{
							"mobile": u.Mobile,
							"type":   "login",
						})

					var rsp map[string]interface{}
					gout.POST("https://dev.tiktok.api.vodeshop.com/api/v1/auth/login/sms").
						SetJSON(gout.H{
							"mobile":      u.Mobile,
							"mobile_code": "111111",
						}).
						BindJSON(&rsp).
						Do()

					//fmt.Println("rsp：", rsp)
					token_info := (rsp["data"]).(map[string]interface{})
					lock.Lock()
					//token_map.Store(u.Id, token_info["token"].(string))
					token_list = append(token_list, token_info["token"].(string))
					lock.Unlock()
					//token_chan <- token_info["token"].(string)
					twg.Done()
				}
			}()
		}
		twg.Wait()
		var end_time int64 = time.Now().UnixNano() / 1e6
		fmt.Println("获取token总时长：", end_time-start_time)
		//close(token_chan)
		//}()

		var (
			count     int32 = 0
			err_count int32 = 0
		)

		//length := len(token_chan)
		length := len(token_list)
		fmt.Println("token_chan_len：", length)

		var wg sync.WaitGroup
		//var rwlock sync.RWMutex
		wg.Add(length)
		//for _, token := range token_list {
		//	token := token
		for i := 0; i < length; i++ {
			//time.Sleep(time.Duration(3) * time.Second)

			index := i

			go func() {
				defer func() {
					if err := recover(); err != nil {
						atomic.AddInt32(&err_count, 1)
						fmt.Println("receive err：", err, err_count)
						wg.Done()
					}
				}()

				////for tc := range token_chan {
				//for {
				//	tc, ok := <-token_chan
				//	if !ok {
				//		break
				//	}

				//	//select {
				//	//case tc, ok := <-token_chan:
				//	//	if !ok {
				//	//		break
				//	//	}
				//
				//	var res map[string]interface{}
				//	gout.POST("https://dev.tiktok.api.vodeshop.com/api/v1/o2o/order").
				//		SetHeader(gout.H{
				//			//"authorization": "Bearer " + token,
				//			"authorization": "Bearer " + tc,
				//		}).
				//		SetJSON(gout.H{
				//			"goods_num": 1,
				//			"goods_id":  "14",
				//		}).
				//		BindJSON(&res).
				//		Do()
				//
				//	fmt.Println("res：", res)
				//	info := res["data"].(map[string]interface{})
				//	fmt.Println(res["msg"].(string), info["id"].(float64))
				//	wg.Done()
				//	//}
				//}

				//for tc := range token_chan {

				//for {
				//	tc, ok := <-token_chan
				//	if !ok {
				//		break
				//	}

				//select {
				//case tc, ok := <-token_chan:
				//	if !ok {
				//		break
				//	}

				//rwlock.RLock()
				//token := token_list[index]
				//rwlock.RUnlock()

				var start_time_envelope int64 = time.Now().UnixNano() / 1e6
				var envelopes_code int
				var envelopes_res map[string]interface{}
				gout.GET("https://dev.tiktok.api.vodeshop.com/api/v1/red-envelopes/" + strconv.Itoa(factor[1])).
					SetHeader(gout.H{
						//"Authorization": "Bearer " + tc,
						"Authorization": "Bearer " + token_list[index],
						//"Authorization": "Bearer " + token,
					}).
					Code(&envelopes_code).
					BindJSON(&envelopes_res).
					Do()
				//fmt.Print("red-envelopes：", envelopes_res, "	")
				red_info := envelopes_res["data"].(map[string]interface{})
				red_id := red_info["id"].(float64)
				delete(envelopes_res, "data")
				fmt.Print("red-envelopes：", envelopes_code, "  ", envelopes_res, "  ")
				var end_time_envelope int64 = time.Now().UnixNano() / 1e6
				take_up_time_envelope := end_time_envelope - start_time_envelope
				fmt.Println(take_up_time_envelope, "ms")

				var start_time_receive int64 = time.Now().UnixNano() / 1e6
				var receive_code int
				//var receive_body string
				var receive_res map[string]interface{}
				gout.POST("https://dev.tiktok.api.vodeshop.com/api/v1/red-envelopes/receive").
					SetHeader(gout.H{
						//"Authorization": "Bearer " + tc,
						"Authorization": "Bearer " + token_list[index],
						//"Authorization": "Bearer " + token,
					}).
					SetJSON(gout.H{
						"id": strconv.FormatFloat(red_id, 'f', -1, 32),
					}).
					Code(&receive_code).
					BindJSON(&receive_res).
					//BindBody(&receive_body).
					Do()
				//fmt.Println("receive_body：", receive_body)
				fmt.Print("receive：", receive_code, "  ", receive_res, "  ")
				var end_time_receive int64 = time.Now().UnixNano() / 1e6
				take_up_time_receive := end_time_receive - start_time_receive
				fmt.Println(take_up_time_receive, "ms", count)

				if receive_res["code"].(float64) != 1000 {
					atomic.AddInt32(&err_count, 1)
				} else {
					atomic.AddInt32(&count, 1)
				}

				wg.Done()
				//}
				//}
			}()
		}

		wg.Wait()
		fmt.Println("count：", count)
		fmt.Println("err_count：", err_count)
	}
}
